home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / mm / forkexit.c < prev    next >
C/C++ Source or Header  |  1990-07-15  |  10KB  |  292 lines

  1. /* This file deals with creating processes (via FORK) and deleting them (via
  2.  * EXIT/WAIT).  When a process forks, a new slot in the 'mproc' table is
  3.  * allocated for it, and a copy of the parent's core image is made for the
  4.  * child.  Then the kernel and file system are informed.  A process is removed
  5.  * from the 'mproc' table when two events have occurred: (1) it has exited or
  6.  * been killed by a signal, and (2) the parent has done a WAIT.  If the process
  7.  * exits first, it continues to occupy a slot until the parent does a WAIT.
  8.  *
  9.  * The entry points into this file are:
  10.  *   do_fork:    perform the FORK system call
  11.  *   do_mm_exit:    perform the EXIT system call (by calling mm_exit())
  12.  *   mm_exit:    actually do the exiting
  13.  *   do_wait:    perform the WAIT system call
  14.  */
  15.  
  16.  
  17. #include "mm.h"
  18. #include <minix/callnr.h>
  19. #include "mproc.h"
  20. #include "param.h"
  21.  
  22. #define LAST_FEW            2    /* last few slots reserved for superuser */
  23.  
  24. PRIVATE next_pid = INIT_PID+1;    /* next pid to be assigned */
  25.  
  26. FORWARD void cleanup();
  27.  
  28. /*===========================================================================*
  29.  *                do_fork                         *
  30.  *===========================================================================*/
  31. PUBLIC int do_fork()
  32. {
  33. /* The process pointed to by 'mp' has forked.  Create a child process. */
  34.  
  35.   register struct mproc *rmp;    /* pointer to parent */
  36.   register struct mproc *rmc;    /* pointer to child */
  37.   int i, child_nr, t;
  38.   char *sptr, *dptr;
  39.   phys_clicks prog_clicks, child_base;
  40. #if (CHIP == INTEL)
  41.   long prog_bytes;
  42.   long parent_abs, child_abs;
  43. #endif
  44.  
  45.  /* If tables might fill up during FORK, don't even start since recovery half
  46.   * way through is such a nuisance.
  47.   */
  48.  
  49.   rmp = mp;
  50.   if (procs_in_use == NR_PROCS) return(EAGAIN);
  51.   if (procs_in_use >= NR_PROCS - LAST_FEW && rmp->mp_effuid != 0)return(EAGAIN);
  52.  
  53.   /* Determine how much memory to allocate. */
  54.   prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
  55.   prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
  56. #if (CHIP == INTEL)
  57.   if (rmp->mp_flags & SEPARATE) prog_clicks += rmp->mp_seg[T].mem_len;
  58.   prog_bytes = (long) prog_clicks << CLICK_SHIFT;
  59. #endif
  60.   if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(EAGAIN);
  61.  
  62. #if (CHIP == INTEL)
  63.   /* Create a copy of the parent's core image for the child. */
  64.   child_abs = (long) child_base << CLICK_SHIFT;
  65.   parent_abs = (long) rmp->mp_seg[T].mem_phys << CLICK_SHIFT;
  66.   i = mem_copy(ABS, 0, parent_abs, ABS, 0, child_abs, prog_bytes);
  67.   if ( i < 0) panic("do_fork can't copy", i);
  68. #endif
  69.  
  70.   /* Find a slot in 'mproc' for the child process.  A slot must exist. */
  71.   for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
  72.     if ( (rmc->mp_flags & IN_USE) == 0) break;
  73.  
  74.   /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
  75.   child_nr = (int)(rmc - mproc);    /* slot number of the child */
  76.   procs_in_use++;
  77.   sptr = (char *) rmp;        /* pointer to parent's 'mproc' slot */
  78.   dptr = (char *) rmc;        /* pointer to child's 'mproc' slot */
  79.   i = sizeof(struct mproc);    /* number of bytes in a proc slot. */
  80.   while (i--) *dptr++ = *sptr++;/* copy from parent slot to child's */
  81.  
  82.   rmc->mp_parent = who;        /* record child's parent */
  83.   rmc->mp_flags &= ~TRACED;    /* child does not inherit trace status */
  84. #if (CHIP == INTEL)
  85.   rmc->mp_seg[T].mem_phys = child_base;
  86.   rmc->mp_seg[D].mem_phys = child_base + rmc->mp_seg[T].mem_len;
  87.   rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + 
  88.             (rmp->mp_seg[S].mem_phys - rmp->mp_seg[D].mem_phys);
  89. #endif
  90.   rmc->mp_exitstatus = 0;
  91.   rmc->mp_sigstatus = 0;
  92.  
  93.   /* Find a free pid for the child and put it in the table. */
  94.   do {
  95.     t = 0;            /* 't' = 0 means pid still free */
  96.     next_pid = (next_pid < 30000 ? next_pid + 1 : INIT_PID + 1);
  97.     for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
  98.         if (rmp->mp_pid == next_pid || rmp->mp_procgrp == next_pid) {
  99.             t = 1;
  100.             break;
  101.         }
  102.     rmc->mp_pid = next_pid;    /* assign pid to child */
  103.   } while (t);
  104.  
  105.   /* Set process group. */
  106.   if (who == INIT_PROC_NR) rmc->mp_procgrp = rmc->mp_pid;
  107.  
  108.   /* Tell kernel and file system about the (now successful) FORK. */
  109. #if (CHIP == M68000)
  110.   sys_fork(who, child_nr, rmc->mp_pid, child_base);
  111. #else
  112.   sys_fork(who, child_nr, rmc->mp_pid);
  113. #endif
  114.  
  115.   tell_fs(FORK, who, child_nr, rmc->mp_pid);
  116.  
  117. #if (CHIP == INTEL)
  118.   /* Report child's memory map to kernel. */
  119.   sys_newmap(child_nr, rmc->mp_seg);
  120. #endif
  121.  
  122.   /* Reply to child to wake it up. */
  123.   reply(child_nr, 0, 0, NIL_PTR);
  124.   return(next_pid);         /* child's pid */
  125. }
  126.  
  127.  
  128. /*===========================================================================*
  129.  *                do_mm_exit                     *
  130.  *===========================================================================*/
  131. PUBLIC int do_mm_exit()
  132. {
  133. /* Perform the exit(status) system call. The real work is done by mm_exit(),
  134.  * which is also called when a process is killed by a signal.
  135.  */
  136.  
  137.   mm_exit(mp, status);
  138.   dont_reply = TRUE;        /* don't reply to newly terminated process */
  139.   return(OK);            /* pro forma return code */
  140. }
  141.  
  142.  
  143. /*===========================================================================*
  144.  *                mm_exit                         *
  145.  *===========================================================================*/
  146. PUBLIC void mm_exit(rmp, exit_status)
  147. register struct mproc *rmp;    /* pointer to the process to be terminated */
  148. int exit_status;        /* the process' exit status (for parent) */
  149. {
  150. /* A process is done.  If parent is waiting for it, clean it up, else hang. */
  151. #if (CHIP == M68000)
  152.   phys_clicks base, size;
  153. #else
  154.   phys_clicks s;
  155. #endif
  156.   register int proc_nr = (int)(rmp - mproc);
  157.  
  158.   /* How to terminate a process is determined by whether or not the
  159.    * parent process has already done a WAIT.  Test to see if it has.
  160.    */
  161.   rmp->mp_exitstatus = (char) exit_status;    /* store status in 'mproc' */
  162.  
  163.   if (mproc[rmp->mp_parent].mp_flags & WAITING)
  164.     cleanup(rmp);        /* release parent and tell everybody */
  165.   else
  166.     rmp->mp_flags |= HANGING;    /* Parent not waiting.  Suspend proc */
  167.  
  168.   /* If the exited process has a timer pending, kill it. */
  169.   if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);
  170.  
  171. #if AM_KERNEL
  172. /* see if an amoeba transaction was pending or a putrep needed to be done */
  173.   am_check_sig(proc_nr, 1);
  174. #endif
  175.  
  176.   /* Tell the kernel and FS that the process is no longer runnable. */
  177. #if (CHIP == M68000)
  178.   sys_xit(rmp->mp_parent, proc_nr, &base, &size);
  179.   free_mem(base, size);
  180. #else
  181.   sys_xit(rmp->mp_parent, proc_nr);
  182. #endif
  183.   tell_fs(EXIT, proc_nr, 0, 0);  /* file system can free the proc slot */
  184.  
  185. #if (CHIP == INTEL)
  186.   /* Release the memory occupied by the child. */
  187.   s = (phys_clicks) rmp->mp_seg[S].mem_len;
  188.   s += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
  189.   if (rmp->mp_flags & SEPARATE) s += rmp->mp_seg[T].mem_len;
  190.   free_mem(rmp->mp_seg[T].mem_phys, s);    /* free the memory */
  191. #endif
  192.  
  193. }
  194.  
  195.  
  196. /*===========================================================================*
  197.  *                do_wait                         *
  198.  *===========================================================================*/
  199. PUBLIC int do_wait()
  200. {
  201. /* A process wants to wait for a child to terminate. If one is already waiting,
  202.  * go clean it up and let this WAIT call terminate.  Otherwise, really wait.
  203.  */
  204.  
  205.   register struct mproc *rp;
  206.   register int children;
  207.  
  208.   /* A process calling WAIT never gets a reply in the usual way via the
  209.    * reply() in the main loop.  If a child has already exited, the routine
  210.    * cleanup() sends the reply to awaken the caller.
  211.    */
  212.  
  213.   /* Is there a child waiting to be collected? */
  214.   children = 0;
  215.   for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
  216.     if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
  217.         children++;
  218.         if (rp->mp_flags & HANGING) {
  219.             cleanup(rp);    /* a child has already exited */
  220.             dont_reply = TRUE;
  221.             return(OK);
  222.         }
  223.         if (rp->mp_flags & STOPPED && rp->mp_sigstatus) {
  224.             reply(who, rp->mp_pid, 0177 | (rp->mp_sigstatus << 8),
  225.                 NIL_PTR);
  226.             dont_reply = TRUE;
  227.             rp->mp_sigstatus = 0;
  228.             return(OK);
  229.         }
  230.     }
  231.   }
  232.  
  233.   /* No child has exited.  Wait for one, unless none exists. */
  234.   if (children > 0) {        /* does this process have any children? */
  235.     mp->mp_flags |= WAITING;
  236.     dont_reply = TRUE;
  237.     return(OK);        /* yes - wait for one to exit */
  238.   } else
  239.     return(ECHILD);        /